package atlantik.game;

import java.awt.Color;
import java.awt.Image;

import atlantik.game.action.BoundAction;
import atlantik.game.action.BoundActionFactory;

public class Estate extends AtlantikIdHolder<Integer, Estate> {

	public static final int MAX_HOUSES = 5;

	public Estate(Atlantik client) {
		super(client);
	}

	public enum Action implements BoundActionFactory<EstateAction, Estate> {
		BUY {
			public EstateAction getActionInstance(Atlantik client,
					Estate estate) {
				return estate.new BuyAction(client);
			}
		},
		MORTGAGE {
			public EstateAction getActionInstance(Atlantik client,
					Estate estate) {
				return estate.new MortgageAction(client);
			}
		},
		UNMORTGAGE {
			public EstateAction getActionInstance(Atlantik client,
					Estate estate) {
				return estate.new UnmortgageAction(client);
			}
		},
		BUY_HOUSE {
			public EstateAction getActionInstance(Atlantik client,
					Estate estate) {
				return estate.new BuyHouseAction(client);
			}
		},
		BUY_HOTEL {
			public EstateAction getActionInstance(Atlantik client,
					Estate estate) {
				return estate.new BuyHotelAction(client);
			}
		},
		SELL_HOUSE {
			public EstateAction getActionInstance(Atlantik client,
					Estate estate) {
				return estate.new SellHouseAction(client);
			}
		},
		SELL_HOTEL {
			public EstateAction getActionInstance(Atlantik client,
					Estate estate) {
				return estate.new SellHotelAction(client);
			}
		};
	}

	private String name;

	private Color color;

	private Color bgColor;

	private Image icon;

	private Player owner;

	private int houses;

	private boolean isMortgaged;

	private EstateGroup group;

	private boolean canToggleMortgage;

	private boolean canBeOwned;

	private boolean canBuyHouses;

	private boolean canSellHouses;

	private int price;

	private int mortgagePrice;

	private int unmortgagePrice;

	private int money;

	private int[] rents = new int[MAX_HOUSES + 1];

	private int housePrice;

	public String getName() {
		return name;
	}

	public Color getColor() {
		return color;
	}

	public Color getBackgroundColor() {
		return bgColor;
	}

	public Image getIcon() {
		return icon;
	}

	public Player getOwner() {
		return owner;
	}

	public int getHouses() {
		return houses;
	}

	public boolean isMortgaged() {
		return isMortgaged;
	}

	public EstateGroup getGroup() {
		return group;
	}

	public boolean canToggleMortgage() {
		return canToggleMortgage;
	}

	public boolean canBeOwned() {
		return canBeOwned;
	}

	public boolean canBuyHouses() {
		return canBuyHouses;
	}

	public boolean canSellHouses() {
		return canSellHouses;
	}

	public int getPrice() {
		return price;
	}

	public int getMortgagePrice() {
		return mortgagePrice;
	}

	public int getUnmortgagePrice() {
		return unmortgagePrice;
	}

	public int getMoney() {
		return money;
	}

	public int getHousePrice() {
		return housePrice;
	}

	public int getRent() {
		return rents[houses];
	}

	void setName(String name) {
		this.name = name;
	}

	void setColor(Color color) {
		this.color = color;
	}

	public void setBackgroundColor(Color bgColor) {
		this.bgColor = bgColor;
	}

	void setIcon(Image icon) {
		this.icon = icon;
	}

	void setOwner(Player owner) {
		this.owner = owner;
	}

	void setHouses(int houses) {
		this.houses = houses;
	}

	public void setMortgaged(boolean isMortgaged) {
		this.isMortgaged = isMortgaged;
	}

	void setGroup(EstateGroup group) {
		this.group = group;
	}

	void setCanToggleMortgage(boolean canToggleMortgage) {
		this.canToggleMortgage = canToggleMortgage;
	}

	void setCanBeOwned(boolean canBeOwned) {
		this.canBeOwned = canBeOwned;
	}

	void setCanBuyHouses(boolean canBuyHouses) {
		this.canBuyHouses = canBuyHouses;
	}

	void setCanSellHouses(boolean canSellHouses) {
		this.canSellHouses = canSellHouses;
	}

	void setPrice(int price) {
		this.price = price;
	}

	void setMortgagePrice(int mortgagePrice) {
		this.mortgagePrice = mortgagePrice;
	}

	void setUnmortgagePrice(int unmortgagePrice) {
		this.unmortgagePrice = unmortgagePrice;
	}

	void setMoney(int money) {
		this.money = money;
	}

	void setHousePrice(int housePrice) {
		this.housePrice = housePrice;
	}

	void setRent(int houses, int rent) {
		this.rents[houses] = rent;
	}

	public abstract class EstateAction extends BoundAction<EstateAction, Estate> {
		private final String caption;
		public EstateAction(Atlantik client, String caption) {
			super(client, Estate.this);
			this.caption = caption;
		}
		@Override
		public String getCaption() {
			return caption;
		}
	}

	private class BuyAction extends EstateAction {
		public BuyAction(Atlantik client) {
			super(client, "Buy");
		}

		public void perform() {
			client.buyEstate();
		}

		public boolean canPerform() {
			return super.canPerform() && self().canBuyEstate() && self().getLocation() == item
					&& item.canBeOwned();
		}
	}

	private class MortgageAction extends EstateAction {
		public MortgageAction(Atlantik client) {
			super(client, "Mortgage");
		}

		public void perform() {
			client.estateToggleMortgage(item);
		}

		public boolean canPerform() {
			return super.canPerform() && item.canToggleMortgage() && !item.isMortgaged();
		}
	}

	private class UnmortgageAction extends EstateAction {
		public UnmortgageAction(Atlantik client) {
			super(client, "Unmortgage");
		}

		public void perform() {
			client.estateToggleMortgage(item);
		}

		public boolean canPerform() {
			return super.canPerform() && item.canToggleMortgage() && item.isMortgaged();
		}
	}

	private class BuyHouseAction extends EstateAction {
		public BuyHouseAction(Atlantik client) {
			super(client, "Buy house");
		}

		public void perform() {
			client.estateHouseBuy(item);
		}

		public boolean canPerform() {
			return super.canPerform() && self().equals(item.getOwner()) && item.canBuyHouses()
					&& item.getHouses() < MAX_HOUSES - 1;
		}
	}

	private class SellHouseAction extends EstateAction {
		public SellHouseAction(Atlantik client) {
			super(client, "Sell house");
		}

		public void perform() {
			client.estateHouseSell(item);
		}

		public boolean canPerform() {
			return super.canPerform() && self().equals(item.getOwner()) && item.canBuyHouses()
					&& item.getHouses() < MAX_HOUSES;
		}
	}

	private class BuyHotelAction extends EstateAction {
		public BuyHotelAction(Atlantik client) {
			super(client, "Buy hotel");
		}

		public void perform() {
			client.estateHouseBuy(item);
		}

		public boolean canPerform() {
			return super.canPerform() && self().equals(item.getOwner()) && item.canBuyHouses()
					&& item.getHouses() == MAX_HOUSES - 1;
		}
	}

	private class SellHotelAction extends EstateAction {
		public SellHotelAction(Atlantik client) {
			super(client, "Sell hotel");
		}

		public void perform() {
			client.estateHouseSell(item);
		}

		public boolean canPerform() {
			return super.canPerform() && self().equals(item.getOwner()) && item.canBuyHouses()
					&& item.getHouses() == MAX_HOUSES;
		}
	}

}
